import { WebSocket } from 'ws';
import { v4 as uuidv4 } from 'uuid';
import ProtoMessageHandler from '../proto/ProtoMessageHandler';
import log from 'electron-log/main';

export class WebSocketClient {
  private ws: WebSocket;
  private reconnectInterval: number = 1000; // 初始重连间隔时间为1秒
  private maxReconnectInterval: number = 30000; // 最大重连间隔为30秒
  private heartbeatInterval: number = 50000; // 发送心跳包的时间间隔，单位是毫秒
  private heartbeatTimer: NodeJS.Timeout | null = null; // 保存心跳包定时器
  private onBinaryMessageCallback: ((binaryData: Buffer) => void) | null = null;
  private onErrorCallback: ((error: Error) => void) | null = null;
  private static senderIdCounter = 0;

  private destroyed: boolean = false; // 标记是否已销毁

  constructor(
    private readonly serverUrl: string,
    private readonly shouldReconnect: boolean = true,
    private readonly shouldSendHeartbeat: boolean = true,
  ) {}

  setOnBinaryMessageCallback(
    onBinaryMessageCallback: (binaryData: Buffer) => void,
  ) {
    this.onBinaryMessageCallback = onBinaryMessageCallback;
  }

  setOnErrorCallback(onErrorCallback: (error: Error) => void) {
    this.onErrorCallback = onErrorCallback;
  }

  // 检查WebSocket是否已连接
  isConnected(): boolean {
    return this.ws && this.ws.readyState === WebSocket.OPEN;
  }

  // 连接到 WebSocket 服务器
  connect() {
    log.info('正在连接到 WebSocket 服务器...');

    this.ws = new WebSocket(this.serverUrl);

    this.ws.on('open', () => {
      log.info('WebSocket 已连接');
      this.reconnectInterval = 1000; // 重连成功后重置重连间隔
      if (this.shouldSendHeartbeat) {
        this.startHeartbeat(); // 连接成功后启动心跳包
      }
    });

    this.ws.on('message', (data: WebSocket.Data, isBinary) => {
      try {
        if (isBinary) {
          // 检查回调是否存在
          if (this.onBinaryMessageCallback) {
            this.onBinaryMessageCallback(data as Buffer);
          }
        } else {
          this.handleTextMessage(data.toString());
        }
      } catch (error) {
        log.error('处理消息时出错:', error);
        this.handleError(error);
      }
    });

    this.ws.on('close', () => {
      log.info('WebSocket 已断开');
      this.stopHeartbeat(); // 连接断开后停止心跳包
      if (this.shouldReconnect && !this.destroyed) {
        this.reconnect();
      }
    });

    this.ws.on('error', (error: Error) => {
      log.error(`WebSocket 错误: ${error.message}`);
      if (this.ws?.readyState !== WebSocket.OPEN) {
        this.stopHeartbeat(); // 错误时停止心跳包
        if (this.shouldReconnect && !this.destroyed) {
          this.reconnect();
        }
      }
      this.handleError(error);
    });
  }

  private handleError(error: Error) {
    if (this.onErrorCallback) {
      this.onErrorCallback(error);
    }
  }

  private handleTextMessage(text: string) {
    log.info(`收到文本消息: ${text}`);
  }

  // 重连逻辑
  private reconnect() {
    log.info(`将在 ${this.reconnectInterval / 1000} 秒后尝试重连...`);
    setTimeout(() => {
      if (this.reconnectInterval < this.maxReconnectInterval) {
        this.reconnectInterval *= 2; // 增加重连间隔，逐步加倍
      }
      this.connect(); // 重新连接
    }, this.reconnectInterval);
  }

  // 心跳包发送函数
  private startHeartbeat() {
    this.stopHeartbeat(); // 确保之前的定时器已被清除
    this.heartbeatTimer = setInterval(() => {
      if (this.ws?.readyState === WebSocket.OPEN) {
        this.ws.send('ping'); // 发送心跳包，内容为 'ping'
      }
    }, this.heartbeatInterval);
  }

  // 停止心跳包
  private stopHeartbeat() {
    if (this.heartbeatTimer) {
      clearInterval(this.heartbeatTimer);
      this.heartbeatTimer = null;
    }
  }

  // 生成请求 ID
  private static generateSenderId(): string {
    // return (++WebSocketClient.senderIdCounter).toString();

    // 方法2：UUID (更复杂，但更加唯一)
    return uuidv4();
  }

  // 发送请求
  sendRequest(str: string | Buffer, dataType: string = 'json') {
    if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
      log.error('WebSocket 未打开');
      return;
    }

    const requestId = WebSocketClient.generateSenderId();
    const data = Buffer.from(JSON.stringify({ message: str }));
    const timestamp = Date.now();
    const request = ProtoMessageHandler.createRequest(
      requestId,
      data,
      timestamp,
      dataType,
    );
    const encodedRequest = ProtoMessageHandler.encodeRequest(request);
    this.ws.send(encodedRequest);
    log.info(`已发送请求，ID: ${requestId}`);
  }

  // 发送通知
  sendNotification(type: number, str: string | Buffer) {
    if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
      log.error('WebSocket 未打开');
      return;
    }

    const timestamp = Date.now();
    const message = Buffer.from(str);
    const notification = ProtoMessageHandler.createNotification(
      type,
      message,
      timestamp,
    );
    const encodedNotification =
      ProtoMessageHandler.encodeNotification(notification);
    this.ws.send(encodedNotification);
  }

  // 断开连接
  disconnect(destroy: boolean = false) {
    this.destroyed = destroy;
    this.stopHeartbeat();
    if (this.ws && this.ws.readyState === WebSocket.OPEN) {
      this.ws.close();
      log.info('连接已关闭');
    }
  }
}
